
package asteval

import "math/big"

const (
  number byte = iota
  variable
  unary
  binary
)

//type Environment map[string]*big.Int

type Expression struct {
  class byte
  value *big.Int
  varname string
  operation rune
  first, second *Expression
}

func Number(num string) *Expression {
  nm := new(big.Int)
  nm.SetString(num, 10)
  return &Expression{class: number, value: nm}
}

func Variable(nam string) *Expression {
  return &Expression{class: variable, varname: nam}
}

func Unary(op rune, ex *Expression) *Expression {
  return &Expression{class: unary, operation: op, first: ex}
}

func Binary(op rune, exo, exi *Expression) *Expression {
  return &Expression{class: binary, operation: op, first: exo, second: exi}
}

func (e *Expression) Evaluate() *big.Int {
  var res *big.Int = new(big.Int) 
  
  switch e.class {
    case number:
      res.Set(e.value)
    case unary:
      res = e.first.Evaluate()
      if '-' == e.operation { res.Neg(res) }
    case binary:
      exo := e.first.Evaluate()
      exi := e.second.Evaluate()
      switch e.operation {
        case '+': res.Add(exo, exi)
        case '-': res.Sub(exo, exi)
        case '*': res.Mul(exo, exi)
        case '/': res.Div(exo, exi)
      }
  }
  
  return res
}
